import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';

class DataSyncService {
  static const String _baseUrl = 'https://api.github.com';
  static const String _repoPath =
      '/repos/silence-3013/fin-track-data/contents/data';
  static const String _githubToken =
      'YOUR_GITHUB_TOKEN'; // Replace with your GitHub token
  static const String _localDataPath = 'path_to_your_local_data_directory';

  final SharedPreferences _prefs;
  late final Dio _dio;

  DataSyncService(this._prefs) {
    _dio = Dio(
      BaseOptions(
        baseUrl: _baseUrl,
        headers: {
          'Accept': 'application/vnd.github.v3+json',
          'Authorization': 'Bearer $_githubToken',
        },
        connectTimeout: const Duration(seconds: 30),
        receiveTimeout: const Duration(seconds: 30),
        sendTimeout: const Duration(seconds: 30),
      ),
    );

    // 添加重试拦截器
    _dio.interceptors.add(
      InterceptorsWrapper(
        onError: (DioException e, ErrorInterceptorHandler handler) async {
          debugPrint('网络请求错误: ${e.type} - ${e.message}');
          if (e.type == DioExceptionType.connectionTimeout ||
              e.type == DioExceptionType.receiveTimeout ||
              e.type == DioExceptionType.sendTimeout ||
              e.type == DioExceptionType.connectionError) {
            // 重试3次
            for (int i = 0; i < 3; i++) {
              try {
                debugPrint('尝试重试请求 (${i + 1}/3)');
                final response = await _dio.request(
                  e.requestOptions.path,
                  data: e.requestOptions.data,
                  queryParameters: e.requestOptions.queryParameters,
                  options: Options(
                    method: e.requestOptions.method,
                    headers: e.requestOptions.headers,
                  ),
                );
                return handler.resolve(response);
              } catch (e) {
                debugPrint('重试失败: $e');
                if (i == 2) {
                  return handler.reject(e as DioException);
                }
                await Future.delayed(const Duration(seconds: 2)); // 增加重试间隔
              }
            }
          }
          return handler.next(e);
        },
      ),
    );
  }

  // 从GitHub获取数据
  Future<Map<String, dynamic>> fetchDataFromGitHub() async {
    try {
      final response = await _dio.get('$_baseUrl$_repoPath/transactions.json');
      if (response.statusCode == 200) {
        final data = response.data;
        if (data is Map<String, dynamic> && data.containsKey('transactions')) {
          await saveDataLocally(data); // 覆盖本地数据
          return data;
        } else {
          throw Exception('下载的数据中缺少transactions字段');
        }
      } else {
        throw Exception('从GitHub获取数据时出错: ${response.statusCode}');
      }
    } catch (e) {
      debugPrint('从GitHub获取数据时出错: $e');
      return await _loadLocalData();
    }
  }

  // 保存数据到本地
  Future<void> saveDataLocally(Map<String, dynamic> data) async {
    try {
      await _prefs.setString('transactions', jsonEncode(data));
    } catch (e) {
      debugPrint('Error saving data locally: $e');
      rethrow;
    }
  }

  // 从本地加载数据
  Map<String, dynamic>? loadLocalData() {
    try {
      final String? data = _prefs.getString('transactions');
      if (data != null) {
        final decoded = jsonDecode(data);
        if (decoded is Map<String, dynamic>) {
          return decoded;
        }
      }
      return null;
    } catch (e) {
      debugPrint('Error loading local data: $e');
      return null;
    }
  }

  // 比较本地数据和GitHub数据
  Future<bool> compareData(Map<String, dynamic> localData) async {
    try {
      final githubData = await fetchDataFromGitHub();
      return mapEquals(localData, githubData);
    } catch (e) {
      debugPrint('Error comparing data: $e');
      return false;
    }
  }

  // 恢复数据
  Future<Map<String, dynamic>> recoverData() async {
    try {
      final githubData = await fetchDataFromGitHub();
      await saveDataLocally(githubData);
      return githubData;
    } catch (e) {
      debugPrint('Error recovering data: $e');
      rethrow;
    }
  }

  // 测试数据同步
  Future<bool> testDataSync() async {
    try {
      final testData = {
        'test': 'data',
        'timestamp': DateTime.now().toIso8601String(),
      };

      // 保存测试数据
      await saveDataLocally(testData);

      // 从本地加载测试数据
      final loadedData = loadLocalData();
      if (loadedData == null) {
        return false;
      }

      // 验证数据完整性
      return mapEquals(testData, loadedData);
    } catch (e) {
      debugPrint('Error testing data sync: $e');
      return false;
    }
  }

  // 上传数据到 GitHub
  Future<void> uploadDataToGitHub(Map<String, dynamic> data) async {
    try {
      // 获取当前文件的SHA
      String? sha;
      try {
        final response = await _dio.get(
          '$_baseUrl$_repoPath/transactions.json',
        );
        if (response.statusCode == 200 && response.data['sha'] != null) {
          sha = response.data['sha'];
        }
      } catch (e) {
        debugPrint('获取文件SHA时出错: $e');
      }

      // 准备请求体
      final body = {
        'message': 'Update transactions data',
        'content': base64Encode(utf8.encode(jsonEncode(data))),
        if (sha != null) 'sha': sha,
      };

      // 上传数据
      final response = await _dio.put(
        '$_baseUrl$_repoPath/transactions.json',
        data: jsonEncode(body),
      );

      if (response.statusCode == 200 || response.statusCode == 201) {
        debugPrint('数据上传成功');
        await saveDataLocally(data);
      } else {
        throw Exception('上传数据失败: HTTP ${response.statusCode}');
      }
    } catch (e) {
      debugPrint('上传数据时出错: $e');
      rethrow;
    }
  }

  Future<Map<String, dynamic>> _loadLocalData() async {
    try {
      final file = File('$_localDataPath/transactions.json');
      if (await file.exists()) {
        final jsonString = await file.readAsString();
        return jsonDecode(jsonString);
      }
    } catch (e) {
      debugPrint('加载本地数据时出错: $e');
    }
    return {'transactions': []};
  }
}
